<?php

declare(strict_types=1);

namespace catcher\platform\order;


use catchAdmin\basics\model\States;
use catchAdmin\order\model\OrderBuyerRecords as orderBuyerRecordsModel;
use catchAdmin\order\model\OrderItemRecords as orderItemRecordsModel;
use catchAdmin\order\model\OrderRecords as orderRecordsModel;
use catchAdmin\product\model\ProductPlatformSku as productPlatformSkuModel;
use catchAdmin\product\model\ProductPrice as productPriceModel;
use catchAdmin\report\model\ReportOrder as reportOrderModel;
use catchAdmin\product\model\ProductCombinationInfo as productCombinationInfoModel;
use catcher\Code;
use think\facade\Log;
use think\facade\Cache;
use Ups\Entity\Address as UpsAddress;
use Ups\AddressValidation as UpsAddressValidation;

class OrderService
{
    protected $productPlatformSkuModel;
    protected $orderBuyerRecordsModel;
    protected $orderItemRecordsModel;
    protected $orderRecordsModel;
    protected $reportOrderModel;
    protected $productPriceModel;
    protected $productCombinationInfoModel;

    public function __construct(
        productPlatformSkuModel $productPlatformSkuModel,
        orderBuyerRecordsModel $orderBuyerRecordsModel,
        orderItemRecordsModel $orderItemRecordsModel,
        orderRecordsModel $orderRecordsModel,
        reportOrderModel $reportOrderModel,
        productPriceModel $productPriceModel,
        productCombinationInfoModel $productCombinationInfoModel
    ) {
        $this->productPlatformSkuModel = $productPlatformSkuModel;
        $this->orderBuyerRecordsModel = $orderBuyerRecordsModel;
        $this->orderItemRecordsModel = $orderItemRecordsModel;
        $this->orderRecordsModel = $orderRecordsModel;
        $this->reportOrderModel = $reportOrderModel;
        $this->productPriceModel = $productPriceModel;
        $this->productCombinationInfoModel = $productCombinationInfoModel;
    }

    /**
     * 转存储到ERP系统的销售订单
     * @param $order
     * @param $item
     * @param int $i 查询起始行，第一行
     * @param int $combination 是否组合商品，默认非组合
     * @param bool $check_address 是否使用UPS验证收货地址，默认验证
     */
    public function saveOrder($order, $item, $i = 1, $combination = 0, $check_address = true)
    {
        try {
//            // 7天之前的订单不同步
//            $timediff = abs(time() - $order['paid_at']);
//            if (intval($timediff / 86400) > 7) {
//                return true;
//            }
            // 加Redis锁
            $idSync = 'syncOrder|' . $order['shop_basics_id'] . $order['platform_no'];
            $isSync = Cache::get($idSync);
            if ($isSync) {
                return true;
            } else {
                Cache::set($idSync, $order['platform_no'], 10);
                // $order['combination'] = $order['combination'] ?? false; // 默認非組合商品
                $order['combination'] = $combination == 1 ? true : false; // 默认非组合
                $this->orderRecordsModel->startTrans();
                // 替换买家姓名中的特殊字符（\&）
                $order['order_buyer']['address_name'] = str_replace(array("&", "\\"), array("*", "*"), $order['order_buyer']['address_name']);
                // 替换买家地址中的多个空格
                $order['order_buyer']['address_street1'] = preg_replace("/\s(?=\s)/", "\\1", $order['order_buyer']['address_street1']);
                $num = $this->orderRecordsModel->findNum(($order['order_buyer']['address_phone']));
                // 替换买家电话位数不足10位替换为10个0
                $order['order_buyer']['address_phone'] = strlen($num) < 10 ? '0000000000' : $order['order_buyer']['address_phone'];
                // 订单拉入进来时，按照商品维度进行拆分到订单，每个商品独立入库一个订单
                foreach ($item as $key => $info) {
                    // 没有sku编码的商品直接跳过
                    if (empty($info['sku'])) {
                        Log::info(sprintf("订单【%s】商品SKU不存在", $order['platform_no']));
                        continue;
                    }
                    if (!$order['combination']) {
                        // 重置订单状态
                        $order['order_type'] = $this->checkOrderType($order, $info, $check_address);
                    }
                    // 组合商品则拆开寫入訂單
                    if ($info['goods_type'] == Code::TYPE_COMBINATION) {
                        // $order['combination'] = true;
                        Cache::delete($idSync);
                        $this->saveOrder($order, $this->checkProductCombination($info), $i, 1);
                        continue;
                    }
                    // 设置订单所属客户ID，来源于商品表的所属客户ID
                    $order['company_id'] = $info['company_id'];
//                    echo $order['company_id'];exit();
//                    echo 'i-'.$i.PHP_EOL;
//                    echo 'info-goods_id:'.$info['goods_id'].PHP_EOL;
//                    echo 'info-sku:'.$info['sku'].PHP_EOL;
                    // 判断订单是否存在(同一平台的相同订单号)
                    if ($i == 1) { // 只判断第一行商品（在拉取平台订单拆单时，第一行商品没存入库可继续，因为存在拆单后重复商品，所以只判断第一个）
                        if ($this->orderRecordsModel->findOrderProduct($order['platform_no'], $info['goods_id'], $order['shop_basics_id'], $info['sku']) > 0) {
                            $this->orderRecordsModel->rollback();
                            Cache::delete($idSync);
                            return true;
                        }
                    }
                    // 商品海运费
                    if ($info['goods_id'] !== 0) {
                        $info['freight_fee'] = $this->productPriceModel
                            ->where(['product_id' => $info['goods_id']])->value('ocean_freight') ?? 0;
                    }
                    // 拆单后重置订单数量为商品数量
                    $order['total_num'] = $info['quantity_purchased'];
                    // 拆单后重置订单价格为商品价格
                    switch ($order['platform_id']) {
                        case Code::AMAZON:
                            $order['total_price'] = bcadd(
                                bcmul(strval($info['transaction_price_value']), strval($info['quantity_purchased']), 4),
                                bcmul(strval($info['tax_amount_value']), strval($info['quantity_purchased']), 4),
                                4
                            ) ?? $order['total_price'];
                            break;
                        default:
                            $order['total_price'] = bcmul(strval($info['transaction_price_value']), strval($info['quantity_purchased']), 4) ?? $order['total_price'];
                            break;
                    }
                    // 拆单后重置订单价格单位
                    $order['currency'] = $info['transaction_price_currencyid'] ?? $order['currency'];
                    // 組合商品价格只在一个订单中展示，其他订单的价格和税费都是0
                    if ($order['combination'] && ($key != 0)) {
                        $order['total_price'] = 0;
                        $order['total_num'] = 0;
                        $info['transaction_price_value'] = 0;
                        $info['tax_amount_value'] = 0;
                        $info['freight_fee'] = 0;
                    }
                    // 入库平台订单返回 订单ID
                    $id = $this->orderRecordsModel->createBy($order);
                    // 入库订单收货人信息表
                    $order['order_buyer']['order_record_id'] = $id;
                    // 检查订单收货人州/省是否简写
                    $order['order_buyer']['address_stateorprovince'] = App(States::class)
                        ->getStates($order['order_buyer']['address_stateorprovince']);
                    $this->orderBuyerRecordsModel->createBy($order['order_buyer']);
                    // 入库订单商品信息表
                    $info['order_record_id'] = $id;
                    $this->orderItemRecordsModel->createBy($info);
                    // FBA订单出库判断(未商品异常)
                    if ($order['order_type'] == Code::ORDER_TYPE_FBA && $order['abnormal'] == 0) {
                        // 出库成功则写入FBA报表
                        if ($this->orderRecordsModel->deliveryFba($id, 1)) {
                            // $this->reportOrderModel->saveOrder('', $id);
                        }
                    }
                    $i++;
                }
                $this->orderRecordsModel->commit();
                Cache::delete($idSync);
                return true;
            }
        } catch (\Exception $e) {
            $this->orderRecordsModel->rollback();
//             Cache::delete($idSync);
            $message = sprintf(
                "添加订单有误，订单【%s-%s】错误信息:【%s】",
                $order['platform'],
                $order['platform_no'],
                $e->getCode() . ':' . $e->getMessage() .
                    ' in ' . $e->getFile() . ' on line ' . $e->getLine()
            );
            Log::info($message);
            throw new \Exception($message);
        }
    }

    /**
     * 验证订单类型并返回，同时通过商品映射平台写入商品信息
     * @param $order
     * @param $item
     * @param $check_address
     * @return int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function checkOrderType(&$order, &$item, $check_address)
    {
        $type = '';
        // 亚马逊的FBA订单只判断是否为商品异常
        if ($order['order_type'] == Code::ORDER_TYPE_FBA) {
            $this->productPlatformSkuModel->getProductBySku($order['shop_basics_id'], $item);
            // 映射商品匹配失败
            if ($item['goods_id'] == 0) {
                // 商品异常
                $order['abnormal'] = Code::ABNORMAL_PRODUCT;
            } else {
                $order['abnormal'] = 0;
            }
            return $order['order_type'];
        }
        if ($check_address) {
            // 1.查询对比地址库信息，todo:
            $type = $this->checkUpsAddress($order);
            // 判断地址异常
            if ($type == Code::ORDER_TYPE_ABNORMAL) {
                // 异常订单类型(1-商品异常; 2-地址异常; 0-正常),
                // 如地址异常则改变订单状态为：地址异常
                $order['abnormal'] = Code::ABNORMAL_ADDRESS;
                return $type;
            }
        }
        // 2.对比组合商品
        // 3.比对商品映射信息是否存在，存在则存储商品的映射信息
        $this->productPlatformSkuModel->getProductBySku($order['shop_basics_id'], $item);
        // 判断商品异常
        // 映射商品匹配失败
        if ($item['goods_id'] == 0) {
            // 商品异常
            $order['abnormal'] = Code::ABNORMAL_PRODUCT;
            // 订单异常
            $type = Code::ORDER_TYPE_ABNORMAL;
            return $type;
        } else {
            $order['abnormal'] = 0;
        }
        // 5.验证是否为预售订单
        if (!empty($preSale = Cache::get(Code::CACHE_PRESALE . $order['shop_basics_id'] . '_' . $item['goods_id']))) {
            $preSale = json_decode($preSale);
            $now = time();
            // 判断是否在预售时间内
            if ($now >= $preSale->start_time && $now <= $preSale->end_time) {
                $order['pre_shipped_at'] = $preSale->estimated_delivery_time;
                $type = Code::ORDER_TYPE_PRESALES;
            }
        }
        return $type;
    }

    /**
     * 调用UPS地址验证接口验证用户地址正确性
     * @param $data
     * @return int
     * @throws \Exception
     */
    public function checkUpsAddress(&$data)
    {
        // 实例化地址类
        $address = new UpsAddress();
        $address->setAddressLine1($data['order_buyer']['address_street1']);
        $address->setAddressLine2($data['order_buyer']['address_street2']);
        $address->setAddressLine3($data['order_buyer']['address_street3']);
        $address->setStateProvinceCode($data['order_buyer']['address_stateorprovince']);
        $address->setCity($data['order_buyer']['address_cityname']);
        $address->setCountryCode($data['order_buyer']['address_country']);
        $address->setPostalCode($data['order_buyer']['address_postalcode']);
        // 实例化地址验证类
        $xav = new UpsAddressValidation(
            config('catch.ups.access_key'),
            config('catch.ups.user_id'),
            config('catch.ups.password')
        );
        try {
            // 非美国地址，直接返回匹配失败
            if ($address->getCountryCode() != 'US') {
                return Code::ORDER_TYPE_ABNORMAL;
            }
            // 判断地址是否存在街道
            if (empty($data['order_buyer']['address_street1'])) {
                $data['remarks'] = '无街道信息，匹配失败';
                return Code::ORDER_TYPE_ABNORMAL;
            }
            $xav->activateReturnObjectOnValidate();
            // 验证地址合法否
            $response = $xav->validate(
                $address,
                $requestOption = UpsAddressValidation::REQUEST_OPTION_ADDRESS_VALIDATION_AND_CLASSIFICATION,
                $maxSuggestion = 2
            );
            // 用户地址无效，且类型是未知
            // if ($response->noCandidates() && $response->getAddressClassification()->code == 0) {
            //     $data['remarks'] = '地址无效，匹配失败';
            //     //Do something clever and helpful to let the use know the address is invalid
            //     // 匹配失败则为异常订单
            //     return Code::ORDER_TYPE_ABNORMAL;
            // }
            $validAddress = (object)[];
            // 地址不够具体,返回UPS“最近”地址
            if ($response->isAmbiguous()) {
                $candidateAddresses = $response->getCandidateAddressList();
                $validAddress = $candidateAddresses[0];
            }
            // 地址正确,返回UPS“官方”地址
            if ($response->isValid()) {
                // 取得UPS验证成功地址并回调
                $validAddress = $response->getValidatedAddress();
            }
            if (count(get_object_vars($validAddress)) > 0) {
                // UPS建议地址
                $data['order_buyer']['ship_street1'] = $validAddress->addressLine ?? '';
                $data['order_buyer']['ship_street2'] = $validAddress->addressLine2 ?? '';
                $data['order_buyer']['ship_street3'] = $validAddress->addressLine3 ?? '';
                $data['order_buyer']['ship_region'] = $validAddress->region ?? '';
                $data['order_buyer']['ship_postalcode'] = $validAddress->postcodePrimaryLow . '-' . $validAddress->postcodeExtendedLow;
                $data['order_buyer']['ship_country'] = $validAddress->countryCode ?? '';
                $data['order_buyer']['ship_stateorprovince'] = $validAddress->politicalDivision1 ?? '';
                $data['order_buyer']['ship_cityname'] = $validAddress->politicalDivision2 ?? '';
            }
            // 匹配成功为销售订单
            return Code::ORDER_TYPE_SALES;
        } catch (\Exception $e) {
            // 匹配异常则为异常订单
            $data['remarks'] = $e->getMessage();
            return Code::ORDER_TYPE_ABNORMAL;
            // 抛出异常
            //            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 重組拆單後的組合商品
     * @param $info
     */
    public function checkProductCombination($info)
    {
        $lists = $this->productCombinationInfoModel->getInfoByCombinationID($info['goods_id']);
        $combination = [];
        foreach ($lists as $list) {
            $combination[] = [
                "item_id" => $info['item_id'], // 商品 id
                "product_code" => $info['product_code'], // 商品编码
                "goods_id" => $list['product_id'],
                "quantity_purchased" => $info['quantity_purchased'] * $list['number'], // 数量
                "transaction_price_currencyid" => $info['transaction_price_currencyid'], //单位
                "transaction_price_value" => $info['transaction_price_value'], // 售价
                "tax_amount_currencyid" => $info['tax_amount_currencyid'],
                "tax_amount_value" => $info['tax_amount_value'], // 税额
                "sku" => $info['sku'], // sku
                "name" => $info['name'], // 产品名称
                "buyer_email" => $info['buyer_email'], // 邮箱
                "buyer_user_firstname" => $info['buyer_user_firstname'], // 姓名
                "buyer_user_lastname" => $info['buyer_user_lastname'],
                "company_id" => $info['company_id'],
                "goods_type" => Code::TYPE_PRODUCT // 拆開後為非組合商品
            ];
        }
        return $combination;
    }
}
